package errors

import (
	"github.com/gin-gonic/gin"
	"net/http"
)

// Error 错误异常，不需要包含data
type Error struct {
	StatusCode int    `json:"-"`
	Code       int    `json:"code"`
	Msg        string `json:"msg"`
}

// 定义一些已知的异常
var (
	ServerError = NewError(http.StatusOK, 500, "server error!")

	UsernamePasswordError = NewError(http.StatusOK, 500, "username or password is incorrect") //用户名或密码错误

	InvalidRequestError          = NewError(http.StatusOK, 500, "invalid_request")           //请求缺少必须的参数，存在无效的参数值，同一个参数出现多次，个税不正确
	UnauthorizedClientError      = NewError(http.StatusOK, 500, "unauthorized_client")       //使用此方式请求授权码时，客户端未被授权
	AccessDeniedError            = NewError(http.StatusOK, 500, "access_denied")             //资源拥有者或者授权服务器拒绝请求
	UnsupportedResponseTypeError = NewError(http.StatusOK, 500, "unsupported_response_type") //授权服务器不支持使用此方法获取授权码
	InvalidScopeError            = NewError(http.StatusOK, 500, "invalid_scope")             //请求范围无效、未知、或者格式错误
	ServerErrorError             = NewError(http.StatusOK, 500, "server_error")              //授权服务器遇到未知的情况，进而不能完成请求。（此错误代码时必须的，因为不能通过 HTTP 重定向，返回 500 错误到客户端）
	TemporarilyUnavailableError  = NewError(http.StatusOK, 500, "temporarily_unavailable")   //由于授权服务器当前不能处理超载或维护状态，导致不能处理请求。（此错误代码时必须的，因为不能通过 HTTP 重定向，返回 503 状态到客户端）

)

// OtherError 其它异常
func OtherError(message string) *Error {
	return NewError(http.StatusOK, 500, message)
}

func (e *Error) Error() string {
	return e.Msg
}

// NewError 2020/4/29 19:19
func NewError(statusCode, state int, msg string) *Error {
	e := &Error{}
	e.StatusCode = statusCode
	e.Code = state
	e.Msg = msg
	return e
}

// ErrorType 获取错误类型，如果不是空，就有错误，写到这里，防止给中间件带来错误意图
func ErrorType(c *gin.Context) (errs *Error) {
	// 解析错误
	if length := len(c.Errors); length > 0 {
		// 始终找第一个错误
		err := c.Errors[0].Err
		if err != nil {
			// 断言错误类型
			if e, ok := err.(*Error); ok {
				// 主动Error类型
				errs = e
			} else if e, ok := err.(error); ok {
				// 其它error类型
				errs = OtherError(e.Error())
			} else {
				// 非error，基本不会走到这里
				errs = ServerError
			}
			return
		}
	}
	return nil
}
